package com.molichuxing.services.utils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSONObject;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.utils.DateUtil;
import com.molichuxing.framework.utils.IpUtil;
import com.molichuxing.services.infrastructure.dto.request.create.WechatpayCreateDto;
import com.molichuxing.services.infrastructure.dto.response.PrepaymentDto;
import com.molichuxing.services.property.sdk.WechatpayTradeTypeEnum;
import com.molichuxing.services.sdk.wxpay.WXPayConfigImpl;
import com.molichuxing.services.sdk.wxpay.WXPayConstants;
import com.molichuxing.services.sdk.wxpay.WXPayConstants.SignType;
import com.molichuxing.services.sdk.wxpay.WXPayUtil;

/**
 * 微信支付工具类
 * 
 * @author zoumingyu
 * @date 2019年10月11日
 *
 */
public class WechatpayUtil {
	private static final Logger logger = LoggerFactory.getLogger(WechatpayUtil.class);
	private final static String PREFIX = "wx";

	/**
	 * 获取微信支付配置
	 * 
	 * @param createDto
	 * @return
	 * @throws Exception
	 */
	public static WXPayConfigImpl getConfig(WechatpayTradeTypeEnum tradeType) throws Exception {
		WXPayConfigImpl config = null;
		// 判断支付类型
		switch (tradeType) {
		case JSAPI:
			// 公众号支付
			config = WXPayConfigImpl.getJsapiInstance();
			break;
		case APPLET:
			// 小程序支付
			config = WXPayConfigImpl.getAppletInstance();
			break;
		case APP:
			// APP支付
			config = WXPayConfigImpl.getAppInstance();
			break;
		case MWEB:
			// H5页面支付
			config = WXPayConfigImpl.getJsapiInstance();
			break;
		case NATIVE:
			// 扫码支付
			config = WXPayConfigImpl.getJsapiInstance();
			break;
		default:
			logger.error("微信支付不支持的支付类型:" + tradeType);
			throw new BizException("微信支付不支持的支付类型:" + tradeType);
		}
		return config;
	}

	/**
	 * 微信统一下单封装参数
	 * 
	 * @param createDto
	 * @return
	 */
	public static Map<String, String> orderPayParams(WechatpayCreateDto createDto) {
		Map<String, String> result = new HashMap<>();
		// 公众号和小程序需要用户openid
		if (WechatpayTradeTypeEnum.JSAPI.equals(createDto.getTradeType())) {
			// 公众号支付
			Assert.notNull(createDto.getIp(), "公众号支付时(JSAPI),openid不能为空");
			// openid
			result.put("openid", createDto.getOpenid());
		} else if (WechatpayTradeTypeEnum.APPLET.equals(createDto.getTradeType())) {
			// 小程序支付
			Assert.notNull(createDto.getIp(), "小程序支付时(APPLET),openid不能为空");
			// openid
			result.put("openid", createDto.getOpenid());
		} else if (WechatpayTradeTypeEnum.NATIVE.equals(createDto.getTradeType())) {
			// 扫码支付， 调用微信支付API的机器IP
			createDto.setIp(IpUtil.localIp());
		}
		Assert.notNull(createDto.getIp(), "终端ip不能为空");
		// 终端ip
		result.put("spbill_create_ip", createDto.getIp());
		// 交易类型
		result.put("trade_type", createDto.getTradeType().toString());
		// 订单总金额(分)
		result.put("total_fee", createDto.getTotalFee().multiply(new BigDecimal(100)).toBigInteger().toString());
		// 商品ID 扫码支付必传
		result.put("product_id", createDto.getProductId());
		// 商品描述
		result.put("body", createDto.getBody());
		// 指定不能使用信用卡支付
		if (createDto.getIsCredit()) {
			result.put("limit_pay", "no_credit");
		}
		// 商户订单号
		result.put("out_trade_no", PREFIX + PaymentUtil.getPayNumber());
		// 默认人民币
		result.put("fee_type", "CNY");
		// 终端设备号(门店号或收银设备ID)，默认请传"WEB"(非必传)
		result.put("device_info", "WEB");
		// 订单生成时间(非必传)
		result.put("time_start", DateUtil.formatTime(createDto.getTimeStart(), "yyyyMMddHHmmss"));
		// 订单失效时间 (非必传)
		if (DateUtil.betweenTwoTime(LocalDateTime.now(), createDto.getTimeExpire(), ChronoUnit.MINUTES) < 1L) {
			result.put("time_expire",
					DateUtil.formatTime(DateUtil.plus(LocalDateTime.now(), 1L, ChronoUnit.MINUTES), "yyyyMMddHHmmss"));
		} else {
			result.put("time_expire", DateUtil.formatTime(createDto.getTimeExpire(), "yyyyMMddHHmmss"));
		}
		// 附加数据
		result.put("attach", createDto.getAttach());

		logger.info("微信统一下单封装参数(" + createDto.getTradeType().toString() + ")：" + JSONObject.toJSONString(result));
		return result;
	}

	/**
	 * 微信统一下单回显参数
	 * 
	 * @param config
	 * @param respData
	 * @return
	 * @throws Exception
	 */
	public static PrepaymentDto orderPayResponseParams(WXPayConfigImpl config, Map<String, String> respData,
			String outTradeNo)
			throws Exception {
		PrepaymentDto result = new PrepaymentDto();
		Map<String, String> repData = new HashMap<>();
		WechatpayTradeTypeEnum tradeType = WechatpayTradeTypeEnum.getEnum(respData.get("trade_type").toUpperCase());
		switch (tradeType) {
		case MWEB:
			// H5支付
			repData.put("mwebUrl", respData.get("mweb_url"));
			break;
		case NATIVE:
			// 扫码支付
			repData.put("codeUrl", respData.get("code_url"));
			break;
		case APP:
			// app支付
			repData.put("appid", config.getAppID());
			repData.put("partnerid", config.getMchID());
			repData.put("prepayid", respData.get("prepay_id"));
			repData.put("noncestr", respData.get("nonce_str"));
			repData.put("package", "Sign=WXPay");
			repData.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
			if (config.getUseSandbox()) {
				// 沙箱环境
				repData.put("sign", WXPayUtil.generateSignature(repData, config.getKey(), SignType.MD5));// 签名
				repData.put("signType", WXPayConstants.MD5);
			} else {
				repData.put("sign", WXPayUtil.generateSignature(repData, config.getKey(), SignType.HMACSHA256));// 签名
				repData.put("signType", WXPayConstants.HMACSHA256);
			}
			repData.put("packageStr", repData.get("package"));
			break;
		default:
			// 公众号支付、小程序支付
			repData.put("appId", config.getAppID());
			repData.put("nonceStr", respData.get("nonce_str"));
			repData.put("package", "prepay_id=" + respData.get("prepay_id"));
			repData.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
			if (config.getUseSandbox()) {
				// 沙箱环境
				repData.put("signType", WXPayConstants.MD5);
				repData.put("sign", WXPayUtil.generateSignature(repData, config.getKey(), SignType.MD5));// 签名
			} else {
				repData.put("signType", WXPayConstants.HMACSHA256);
				repData.put("sign", WXPayUtil.generateSignature(repData, config.getKey(), SignType.HMACSHA256));// 签名
			}
			repData.put("packageStr", repData.get("package"));
		}
		logger.info("微信预支付单返回页面参数(" + respData.get("trade_type") + ")：" + repData.toString());
		result.setRequestData(JSONObject.toJSONString(repData));
		result.setOutTradeNo(outTradeNo);
		return result;
	}

}
